/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.datalayer.daoimpl;

import cz.fi.muni.diplomka.common.enumeration.ResourceType;
import cz.muni.fi.diplomka.datalayer.dao.ShopOfferDao;
import cz.muni.fi.diplomka.datalayer.entity.ShopOfferEntity;
import cz.muni.fi.diplomka.datalayer.util.DbConnector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.graphdb.Transaction;

/**
 *
 * @author Jakub Kutil
 */
public class ShopOfferDaoImpl implements ShopOfferDao {

    @Override
    public void addShopOffer(ShopOfferEntity shopOfferEntity) {
        if (shopOfferEntity == null) {
            throw new IllegalArgumentException("Shop Offer Entity can not be null.");
        }

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            String query = "MATCH (ShopOffer:ShopOffer) RETURN max(ShopOffer.id)";

            Long key = new Long(0);
            ExecutionResult result = engine.execute(query);
            Iterator<Long> number = result.columnAs("max(ShopOffer.id)");
            while (number.hasNext()) {
                key = number.next();
            }

            if (key == null) {
                key = new Long(0);
            }
            shopOfferEntity.setId(new Long(key + 1));

            params.put("id", shopOfferEntity.getId());
            params.put("cityId", shopOfferEntity.getCityId());
            params.put("playerId", shopOfferEntity.getPlayerId());
            params.put("soldResource", shopOfferEntity.getSoldResource().toString());
            params.put("soldResourceCount", shopOfferEntity.getSoldResourceCount());
            params.put("wantedResource", shopOfferEntity.getWantedResource().toString());
            params.put("wantedResourceCount", shopOfferEntity.getWantedResourceCount());

            query = "MATCH (City:City {id : {cityId}}), (Player:Player {id : {playerId}})"
                    + "CREATE (ShopOffer: ShopOffer {id : {id}, soldResource : {soldResource}, "
                    + "soldResourceCount : {soldResourceCount}, wantedResource : {wantedResource}, "
                    + "wantedResourceCount : {wantedResourceCount}})<-[r:SELLS]-(City) "
                    + "CREATE (ShopOffer)<-[r2:OFFERS]-(Player)";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public void editShopOffer(ShopOfferEntity shopOfferEntity) {
        if (shopOfferEntity == null) {
            throw new IllegalArgumentException("Shop Offer Entity can not be null.");
        }

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("id", shopOfferEntity.getId());
            params.put("soldResource", shopOfferEntity.getSoldResource().toString());
            params.put("soldResourceCount", shopOfferEntity.getSoldResourceCount());
            params.put("wantedResource", shopOfferEntity.getWantedResource().toString());
            params.put("wantedResourceCount", shopOfferEntity.getWantedResourceCount());

            String query = "MATCH (ShopOffer:ShopOffer {id : {id} }) "
                    + "SET ShopOffer.soldResource = {soldResource}, ShopOffer.soldResourceCount = {soldResourceCount}, "
                    + "ShopOffer.wantedResource = {wantedResource}, ShopOffer.wantedResourceCount = {wantedResourceCount}";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public void deleteShopOffer(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("Id can not be null.");
        }

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("id", id);

            String query = "MATCH (ShopOffer:ShopOffer { id : {id}})-[r]-() DELETE ShopOffer,r";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public ShopOfferEntity getShopOfferById(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("Id can not be null.");
        }
        ShopOfferEntity shopOfferEntity = new ShopOfferEntity();
        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();


        try (Transaction t = gds.beginTx()) {
            Map<String, Object> params = new HashMap<>();

            params.put("id", id);

            String query = "MATCH (City:City)-[r:SELLS]->(ShopOffer:ShopOffer {id :{id} })<-[r2:OFFERS]-(Player:Player)"
                    + "RETURN City.id,ShopOffer,Player.id";

            ExecutionResult result = engine.execute(query, params);

            ResourceIterator<Map<String, Object>> offers = result.iterator();

            while (offers.hasNext()) {
                Map<String, Object> row = offers.next();
                Node node = (Node) row.get("ShopOffer");

                shopOfferEntity.setId(new Long(node.getProperty("id").toString()));
                shopOfferEntity.setCityId(new Long(row.get("City.id").toString()));
                shopOfferEntity.setPlayerId(new Long(row.get("Player.id").toString()));
                shopOfferEntity.setSoldResource(ResourceType.valueOf(node.getProperty("soldResource").toString()));
                shopOfferEntity.setSoldResourceCount(Integer.getInteger(node.getProperty("soldResourceCount").toString()));
                shopOfferEntity.setWantedResource(ResourceType.valueOf(node.getProperty("wantedResource").toString()));
                shopOfferEntity.setWantedResourceCount(Integer.valueOf(node.getProperty("wantedResourceCount").toString()));
            }
            t.success();
        }
        return shopOfferEntity;
    }

    @Override
    public List<ShopOfferEntity> getAllShopOffersOfPlayer(Long playerId) {
        if (playerId == null) {
            throw new IllegalArgumentException("Player Id can not be null.");
        }
        List<ShopOfferEntity> shopOffersList = new ArrayList<>();
        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();


        try (Transaction t = gds.beginTx()) {
            Map<String, Object> params = new HashMap<>();

            params.put("id", playerId);

            String query = "MATCH (City:City)-[r:SELLS]->(ShopOffer:ShopOffer)<-[r2:OFFERS]-(Player:Player {id :{id} })"
                    + "RETURN City.id,ShopOffer";

            ExecutionResult result = engine.execute(query, params);

            ResourceIterator<Map<String, Object>> offers = result.iterator();

            while (offers.hasNext()) {
                Map<String, Object> row = offers.next();
                Node node = (Node) row.get("ShopOffer");

                ShopOfferEntity shopOfferEntity = new ShopOfferEntity();
                shopOfferEntity.setId(new Long(node.getProperty("id").toString()));
                shopOfferEntity.setCityId(new Long(row.get("City.id").toString()));
                shopOfferEntity.setPlayerId(playerId);
                shopOfferEntity.setSoldResource(ResourceType.valueOf(node.getProperty("soldResource").toString()));
                shopOfferEntity.setSoldResourceCount(Integer.getInteger(node.getProperty("soldResourceCount").toString()));
                shopOfferEntity.setWantedResource(ResourceType.valueOf(node.getProperty("wantedResource").toString()));
                shopOfferEntity.setWantedResourceCount(Integer.valueOf(node.getProperty("wantedResourceCount").toString()));

                shopOffersList.add(shopOfferEntity);
            }
            t.success();
        }
        return shopOffersList;
    }

    @Override
    public List<ShopOfferEntity> getAllShopOffersNotOfPlayer(Long playerId) {
        if (playerId == null) {
            throw new IllegalArgumentException("Player Id can not be null.");
        }
        List<ShopOfferEntity> shopOffersList = new ArrayList<>();
        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();


        try (Transaction t = gds.beginTx()) {
            Map<String, Object> params = new HashMap<>();

            params.put("id", playerId);

            String query = "MATCH (City:City)-[r:SELLS]->(ShopOffer:ShopOffer)<-[r2:OFFERS]-(Player:Player) "
                    + "WHERE Player.id <> {id} "
                    + "RETURN City.id,ShopOffer,Player.id";

            ExecutionResult result = engine.execute(query, params);

            ResourceIterator<Map<String, Object>> offers = result.iterator();

            while (offers.hasNext()) {
                Map<String, Object> row = offers.next();
                Node node = (Node) row.get("ShopOffer");

                ShopOfferEntity shopOfferEntity = new ShopOfferEntity();
                shopOfferEntity.setId(new Long(node.getProperty("id").toString()));
                shopOfferEntity.setCityId(new Long(row.get("City.id").toString()));
                shopOfferEntity.setPlayerId(new Long(row.get("Player.id").toString()));
                shopOfferEntity.setSoldResource(ResourceType.valueOf(node.getProperty("soldResource").toString()));
                shopOfferEntity.setSoldResourceCount(Integer.getInteger(node.getProperty("soldResourceCount").toString()));
                shopOfferEntity.setWantedResource(ResourceType.valueOf(node.getProperty("wantedResource").toString()));
                shopOfferEntity.setWantedResourceCount(Integer.valueOf(node.getProperty("wantedResourceCount").toString()));

                shopOffersList.add(shopOfferEntity);
            }
            t.success();
        }
        return shopOffersList;
    }
}
